//
//  MBACache.swift
//  bang
//
//  Created by mba on 16/10/13.
//  Copyright © 2016年 mbalib. All rights reserved.
//

import UIKit
import Foundation
import Cache

struct CacheModel: Codable {
    let data: Data
}
public enum MBAExpiry {
    /// Object will be expired in the nearest future
    case never
    /// Object will be expired in the specified amount of seconds
    case seconds(TimeInterval)
    /// Object will be expired on the specified date
    case date(Date)
    
    /// Returns the appropriate date object
    public var expiry: Expiry {
        switch self {
        case .never:
            return Expiry.never
        case .seconds(let seconds):
            return Expiry.seconds(seconds)
        case .date(let date):
            return Expiry.date(date)
        }
    }

    public var isExpired: Bool {
        return expiry.isExpired
    }
}

class MBACache: NSObject {
    static let `default` = MBACache()
    /// Manage storage
    private var storage: Storage<String, CacheModel>?
    /// init
    override init() {
        super.init()
        expiryConfiguration()
    }

    var expiry: MBAExpiry = .never
    
    func expiryConfiguration(expiry: MBAExpiry = .never) {
        self.expiry = expiry
        let diskConfig = DiskConfig(
            name: "MBACache",
            expiry: expiry.expiry
        )
        let memoryConfig = MemoryConfig(expiry: expiry.expiry)
        do {
            storage = try Storage(diskConfig: diskConfig, memoryConfig: memoryConfig, transformer: TransformerFactory.forCodable(ofType: CacheModel.self))
        } catch {
//            DaisyLog(error)
        }
    }
    
    /// 清除所有缓存
    ///
    /// - Parameter completion: completion
    func removeAllCache(completion: @escaping (_ isSuccess: Bool) -> ()) {
        do {
          try storage?.removeAll()
            completion(true)
        } catch {
            completion(false)
        }
//        storage?.async.removeAll(completion: { result in
//            DispatchQueue.main.async {
//                switch result {
//                case .value: completion(true)
//                case .error: completion(false)
//                }
//            }
//        })
    }
    
    /// 根据key值清除缓存
    ///
    /// - Parameters:
    ///   - cacheKey: cacheKey
    ///   - completion: completion
    func removeObjectCache(_ cacheKey: String, completion: @escaping (_ isSuccess: Bool) -> ()) {
        do {
          try storage?.removeObject(forKey: cacheKey)
            completion(true)
        } catch {
            completion(false)
        }
//        storage?.async.removeObject(forKey: cacheKey, completion: { result in
//            DispatchQueue.main.async {
//                switch result {
//                case .value: completion(true)
//                case .error: completion(false)
//                }
//            }
//        })
    }
    
    /// 读取缓存
    ///
    /// - Parameter key: key
    /// - Returns: model
    func objectSync(forKey key: String) -> CacheModel? {
        do{
            return try storage?.object(forKey: key)
        }catch{
            return nil
        }
        
//        do {
//            /// 过期清除缓存
//            if let isExpire = try storage?.isExpiredObject(forKey: key),
//                isExpire
//            {
//                removeObjectCache(key) { _ in }
////                DaisyLog("读取缓存失败： - 缓存过期")
//                return nil
//            } else {
////                DaisyLog("读取缓存成功")
//                return try storage?.object(forKey: key)
//            }
//        } catch {
////            DaisyLog("读取缓存失败：- 无缓存")
//            return nil
//        }
    }
    
    /// 异步缓存
    ///
    /// - Parameters:
    ///   - object: model
    ///   - key: key
    func setObject(_ object: CacheModel, forKey key: String) {
        do{
            try storage?.setObject(object, forKey: key)
        }catch{
//            return nil
        }
//        storage?.async.setObject(object, forKey: key, expiry: nil, completion: { result in
//            switch result {
//            case .value: break
////                DaisyLog("缓存成功")
//            case .error(let error): break
////                DaisyLog("缓存失败: \(error)")
//            }
//        })
    }
}





extension MBACache {
    //统计缓存文件大小
    class func fileSizeOfCache()-> Int {
        // 取出cache文件夹目录 缓存文件都在这个目录下
        let cachePath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first
        //缓存目录路径
//        print(cachePath)
        // 取出文件夹下所有文件数组
        let fileArr = FileManager.default.subpaths(atPath: cachePath!)
        //快速枚举出所有文件名 计算文件大小
        var size = 0
        for file in fileArr! {
            // 把文件名拼接到路径中
            let path = (cachePath)! + "/\(file)"
            // 取出文件属性
            let floder = try! FileManager.default.attributesOfItem(atPath: path)
            // 用元组取出文件大小属性
            for (abc, bcd) in floder {
                // 累加文件大小
                if abc == FileAttributeKey.size {
                    size += (bcd as AnyObject).intValue
                }
            }
        }
        let mm = size / 1024 / 1024
        return mm
    }
    
    
    //删除缓存文件
    class func clearCache() {
        // 取出cache文件夹目录 缓存文件都在这个目录下
        let cachePath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first
        // 取出文件夹下所有文件数组
        let fileArr = FileManager.default.subpaths(atPath: cachePath!)
        // 遍历删除
        for file in fileArr! {
            
            let path = (cachePath)! + "/\(file)"
            if FileManager.default.fileExists(atPath: path) {
                
                do {
                    try FileManager.default.removeItem(atPath: path)
                } catch {
                    
                }
            }
        }
    }
    
    
    //删除录音缓存文件
    class func clearRecordCache() {
        let docPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first
        let path = (docPath)! + "/record"
        if FileManager.default.fileExists(atPath: path) {
            do {
                try FileManager.default.removeItem(atPath: path)
            } catch {
            }
        }
    }
    
    //删除保存的录音缓存文件
    class func clearSaveRecordCache() {
        let docPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first
        let path = (docPath)! + "/saveRecord"
        if FileManager.default.fileExists(atPath: path) {
            do {
                try FileManager.default.removeItem(atPath: path)
            } catch {
            }
        }
    }
}


//Haneke 改用Cache
//import Haneke
extension MBACache {
    /// 删除haneke 所有缓存
    class func clearHanekeAllCache() {
        MBACache.default.removeAllCache { isSuccess in
            
        }
//        Haneke.Shared.imageCache.removeAll()
//        Haneke.Shared.dataCache.removeAll()
//        Haneke.Shared.stringCache.removeAll()
//        Haneke.Shared.JSONCache.removeAll()
    }
    
    // MARK: - JSON
    class func fetchJson(key: String,
                         compledHandle: @escaping (([String: Any]?) -> () )){
        
        if let data = MBACache.default.objectSync(forKey: key)?.data,
           let json = try? JSONSerialization.jsonObject(with: data, options: [])
        {
            return compledHandle(json as? [String : Any])
        }else{
            return compledHandle(nil)
        }
        
//        let cache = Haneke.Shared.JSONCache
//        cache.fetch(key: key).onSuccess({ (data) in
//            compledHandle(data.dictionary)
//        }).onFailure { (error) in
//            return compledHandle(nil)
//        }
    }
    
    class func setJson(value:[String: Any], key: String) {
        if let jsonData = try? JSONSerialization.data(withJSONObject: value, options: .prettyPrinted) {
            MBACache.default.setObject(CacheModel(data: jsonData), forKey: key)
//            let jsonString = String(data: jsonData, encoding: .utf8)
//            print(jsonString)
        }
//        let cache = Haneke.Shared.JSONCache
//        cache.set(value: Haneke.JSON.Dictionary(value as [String : AnyObject]), key: key)
    }
    
    class func removeJson(key: String) {
        MBACache.default.removeObjectCache(key) { isSuccess in
            
        };
//        let cache = Haneke.Shared.JSONCache
//        cache.remove(key: key)
    }
    
//    // MARK: - String
//    class func fetchString(key: String,
//                           compledHandle: @escaping ((String?) -> () )){
//        let cache = Haneke.Shared.stringCache
//        cache.fetch(key: key).onSuccess({ (data) in
//            compledHandle(data)
//        }).onFailure { (error) in
//            compledHandle(nil)
//        }
//    }
//
//    class func setString(value:String, key: String) {
//        let cache = Haneke.Shared.stringCache
//        cache.set(value: value, key: key)
//    }
//
//    class func removeString(key: String) {
//        let cache = Haneke.Shared.stringCache
//        cache.remove(key: key)
//    }
//
//    // MARK: - Data
    class func fetchData(key: String,
                         compledHandle: @escaping ((Data?) -> () )){
        if let data = MBACache.default.objectSync(forKey: key)?.data
        {
            return compledHandle(data)
        }else{
            return compledHandle(nil)
        }
//        let cache = Haneke.Shared.dataCache
//        cache.fetch(key: key).onSuccess({ (data) in
//            compledHandle(data)
//        }).onFailure { (error) in
//            return compledHandle(nil)
//        }
    }
//
    class func setData(value:Data, key: String) {
        MBACache.default.setObject(CacheModel(data: value), forKey: key)
//        let cache = Haneke.Shared.dataCache
//        cache.set(value: value, key: key)
    }
    
    class func removeData(key: String) {
        MBACache.default.removeObjectCache(key) { isSuccess in
            
        };
//        let cache = Haneke.Shared.dataCache
//        cache.remove(key: key)
    }
//
//    // MARK: - UIImage
//    class func fetchUIImage(key: String,
//                            compledHandle: @escaping ((UIImage?) -> () )){
//        let cache = Haneke.Shared.imageCache
//        cache.fetch(key: key).onSuccess({ (data) in
//            compledHandle(data)
//        }).onFailure { (error) in
//            return compledHandle(nil)
//        }
//    }
//
//    class func setUIImage(value:UIImage, key: String) {
//        let cache = Haneke.Shared.imageCache
//        cache.set(value: value, key: key)
//    }
//
//    class func removeUIImage(key: String) {
//        let cache = Haneke.Shared.imageCache
//        cache.remove(key: key)
//    }

}
